package com.domainchen.framework.core.holder;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.domainchen.framework.core.annotation.Aspect;
import com.domainchen.framework.core.annotation.Service;
import com.domainchen.framework.core.proxy.AspectProxy;
import com.domainchen.framework.core.proxy.Proxy;
import com.domainchen.framework.core.proxy.ProxyManager;
import com.domainchen.framework.core.proxy.transaction.TransactionProxy;

/**
 * @author domainchen or cytxiamen@163.com
 * @version 创建时间：2016年3月15日 下午12:42:22
 * @类说明 切面注解助手类
 */
public class AopHolder {

	private static Logger logger = LoggerFactory.getLogger(AopHolder.class);
	/**
	 * 初始化整个AOP框架
	 */
	static {
		try {
			Map<Class<?>, Set<Class<?>>> proxyMap = createProxyMap();
			Map<Class<?>, List<Proxy>> targetMap = createTargetMap(proxyMap);
			System.out.println("======================================================================================");
			for (Map.Entry<Class<?>, List<Proxy>> targetEntry : targetMap.entrySet()) {
				Class<?> targetClass = targetEntry.getKey();
				List<Proxy> proxyList = targetEntry.getValue();
				// 获取代理对象
				Object proxy = ProxyManager.createProxy(targetClass, proxyList);
				System.out.println("[切面注解]:"+targetClass+"->"+proxy.toString());
				if(StringUtils.isNotEmpty(proxy.toString())){
					BeanHolder.setBean(targetClass, proxy);
				}
				
			}

		} catch (Exception e) {
			logger.error("aop failure", e);
		}
	}

	/**
	 * 获取带有Aspect的所有类
	 * 
	 * @param aspect
	 * @return
	 */
	 private static Set<Class<?>> createTargetClassSet(Aspect aspect) throws Exception {
	        Set<Class<?>> targetClassSet = new HashSet<Class<?>>();
	        Class<? extends Annotation> annotation = aspect.value();
	        if (annotation != null && !annotation.equals(Aspect.class)) {
	            targetClassSet.addAll(ClassHolder.getClassSetByAnnotation(annotation));
	        }
	        return targetClassSet;
	    }

	/**
	 * 获取代理类及其 目标类集合之间的映射关系 一个代理类可对应多个目标类
	 * 
	 * @return
	 * @throws Exception
	 */
	private static Map<Class<?>, Set<Class<?>>> createProxyMap() throws Exception {
		Map<Class<?>, Set<Class<?>>> proxyMap = new HashMap<Class<?>, Set<Class<?>>>();
		/*
		 * // 代理类扩展 AspectProxy抽象类 Set<Class<?>> proxyClassSet =
		 * ClassHolder.getClassSetBySuper(AspectProxy.class); for (Class<?>
		 * proxyClass : proxyClassSet) { // 且带有Aspect注解类 if
		 * (proxyClass.isAnnotationPresent(Aspect.class)) { Aspect aspect =
		 * proxyClass.getAnnotation(Aspect.class); Set<Class<?>> targetClassSet
		 * = createTargetClassSet(aspect); proxyMap.put(proxyClass,
		 * targetClassSet); } }
		 */
		addAspectProxy(proxyMap);
		// 加入事务代理机制
		addTransactionProxy(proxyMap);
		return proxyMap;
	}

	/**
	 * 目标类与代理对象列表之间的映射关系
	 * 
	 * @param proxyMap
	 * @return
	 * @throws Exception
	 */
    private static Map<Class<?>, List<Proxy>> createTargetMap(Map<Class<?>, Set<Class<?>>> proxyMap) throws Exception {
        Map<Class<?>, List<Proxy>> targetMap = new HashMap<Class<?>, List<Proxy>>();
        for (Map.Entry<Class<?>, Set<Class<?>>> proxyEntry : proxyMap.entrySet()) {
            Class<?> proxyClass = proxyEntry.getKey();
            Set<Class<?>> targetClassSet = proxyEntry.getValue();
            for (Class<?> targetClass : targetClassSet) {
                Proxy proxy = (Proxy) proxyClass.newInstance();
                if (targetMap.containsKey(targetClass)) {
                    targetMap.get(targetClass).add(proxy);
                } else {
                    List<Proxy> proxyList = new ArrayList<Proxy>();
                    proxyList.add(proxy);
                    targetMap.put(targetClass, proxyList);
                }
            }
        }
        return targetMap;
    }

	private static void addAspectProxy(Map<Class<?>, Set<Class<?>>> proxyMap) throws Exception {
		// 代理类扩展 AspectProxy抽象类
		Set<Class<?>> proxyClassSet = ClassHolder.getClassSetBySuper(AspectProxy.class);
		for (Class<?> proxyClass : proxyClassSet) {
			// 且带有Aspect注解类
			 if (proxyClass.isAnnotationPresent(Aspect.class)) {
	                Aspect aspect = proxyClass.getAnnotation(Aspect.class);
	                Set<Class<?>> targetClassSet = createTargetClassSet(aspect);
	                proxyMap.put(proxyClass, targetClassSet);
	            }
		}
	}

	private static void addTransactionProxy(Map<Class<?>, Set<Class<?>>> proxyMap) throws Exception {
		Set<Class<?>> serviceClassSet = ClassHolder.getClassSetByAnnotation(Service.class);
		proxyMap.put(TransactionProxy.class, serviceClassSet);
	}
}
